#include "pch.h"
#include "FileIOManager.h"
#include "FileIOTask.h"
#include "..\Common\SRWLock.h"

CFileIOManager *CFileIOManager::m_pThis;

CFileIOManager::CFileIOManager()
	: m_hExitEvent(CreateEvent(NULL, TRUE, FALSE, NULL))
	, m_lockExit(m_hExitEvent, SetEvent)
{
	AssertInUIThread();

	m_pThis = this;
}

CFileIOManager::~CFileIOManager()
{
	AssertInUIThread();
	assert(!m_lockExit);
	assert(m_mapTasks.empty());

	m_pThis = nullptr;
	CloseHandle(m_hExitEvent);
}

bool CFileIOManager::Init()
{
	AssertInUIThread();

	return m_hExitEvent != NULL;
}

void CFileIOManager::Exit()
{
	AssertInUIThread();

	// Notify and wait for all tasks to exit
	CancelTasks();
	std::atomic_store(&m_lockExit, {});
	WaitForSingleObject(m_hExitEvent, INFINITE);
}

void CFileIOManager::AddAndRunTask(const std::shared_ptr<CFileIOTask>& pTask)
{
	AssertInThreadpool();

	auto lockExit = std::atomic_load(&m_lockExit);
	if (!lockExit)
		return;

	CExclusiveLock lock(m_SRWLock);
	m_mapTasks.emplace(pTask->GetId(), pTask);
	lock.Unlock();

	pTask->SetLockExit(std::move(lockExit));
	pTask->Start();
}

void CFileIOManager::RemoveTask(UINT nTaskId)
{
	CExclusiveLock lock(m_SRWLock);

	if (auto it = m_mapTasks.find(nTaskId); it != m_mapTasks.end())
		m_mapTasks.erase(it);
}

void CFileIOManager::CancelTasks()
{
	AssertInUIThread();

	CExclusiveLock lock(m_SRWLock);
	auto mapTasks = std::move(m_mapTasks);
	lock.Unlock();

	for (const auto& [nTaskId, wpTask] : mapTasks)
	{
		if (auto pTask = wpTask.lock())
			pTask->Cancel();
	}
}
